import mongoose from 'mongoose';
import { Permission, IPermission, IPermissionDocument } from '../models/permission';

/**
 * 权限数据访问对象
 * 提供权限相关的数据库操作方法
 */
export class PermissionDAO {
  /**
   * 创建新权限
   * @param permissionData 权限数据
   * @returns 创建的权限文档
   */
  async create(permissionData: Partial<IPermission>): Promise<IPermissionDocument> {
    try {
      const permission = new Permission(permissionData);
      return await permission.save();
    } catch (error: any) {
      if (error.code === 11000) {
        // 处理唯一性约束错误
        const field = Object.keys(error.keyPattern)[0];
        throw new Error(`${field} already exists`);
      }
      throw error;
    }
  }

  /**
   * 根据ID查找权限
   * @param id 权限ID
   * @returns 权限文档或null
   */
  async findById(id: mongoose.Types.ObjectId | string): Promise<IPermissionDocument | null> {
    try {
      if (!id) {
        throw new Error('Permission ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid permission ID format');
      }
      
      return await Permission.findById(id).populate('systemId').populate('parentId');
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据权限编码查找权限
   * @param code 权限编码
   * @returns 权限文档或null
   */
  async findByCode(code: string): Promise<IPermissionDocument | null> {
    try {
      if (!code || typeof code !== 'string') {
        throw new Error('Invalid permission code format');
      }
      return await Permission.findByCode(code);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据权限名称查找权限
   * @param name 权限名称
   * @returns 权限文档或null
   */
  async findByName(name: string): Promise<IPermissionDocument | null> {
    try {
      if (!name || typeof name !== 'string') {
        throw new Error('Invalid permission name format');
      }
      return await Permission.findByName(name);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据系统ID查找权限
   * @param systemId 系统ID
   * @returns 权限文档数组
   */
  async findBySystemId(systemId: mongoose.Types.ObjectId | string): Promise<IPermissionDocument[]> {
    try {
      if (!systemId) {
        throw new Error('System ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(systemId)) {
        throw new Error('Invalid system ID format');
      }
      
      const objectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      return await Permission.findBySystemId(objectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据权限类型查找权限
   * @param type 权限类型
   * @returns 权限文档数组
   */
  async findByType(type: string): Promise<IPermissionDocument[]> {
    try {
      if (!type || typeof type !== 'string') {
        throw new Error('Invalid permission type format');
      }
      
      const validTypes = ['page', 'route', 'component', 'button', 'api', 'data'];
      if (!validTypes.includes(type)) {
        throw new Error('Invalid permission type. Must be one of: page, route, component, button, api, data');
      }
      
      return await Permission.findByType(type);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据父权限ID查找子权限
   * @param parentId 父权限ID
   * @returns 权限文档数组
   */
  async findByParentId(parentId: mongoose.Types.ObjectId | string): Promise<IPermissionDocument[]> {
    try {
      if (!parentId) {
        throw new Error('Parent ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(parentId)) {
        throw new Error('Invalid parent ID format');
      }
      
      const objectId = typeof parentId === 'string' ? new mongoose.Types.ObjectId(parentId) : parentId;
      return await Permission.findByParentId(objectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据状态查找权限
   * @param status 状态
   * @returns 权限文档数组
   */
  async findByStatus(status: number): Promise<IPermissionDocument[]> {
    try {
      if (status !== 0 && status !== 1) {
        throw new Error('Invalid status. Must be 0 (disabled) or 1 (enabled)');
      }
      
      return await Permission.findByStatus(status);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据API路径和方法查找权限
   * @param apiPath API路径
   * @param method HTTP方法
   * @returns 权限文档或null
   */
  async findByApiPath(apiPath: string, method: string): Promise<IPermissionDocument | null> {
    try {
      if (!apiPath || typeof apiPath !== 'string') {
        throw new Error('Invalid API path format');
      }
      
      if (!method || typeof method !== 'string') {
        throw new Error('Invalid HTTP method format');
      }
      
      const validMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'];
      const upperMethod = method.toUpperCase();
      if (!validMethods.includes(upperMethod)) {
        throw new Error('Invalid HTTP method');
      }
      
      return await Permission.findByApiPath(apiPath, upperMethod);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 更新权限
   * @param id 权限ID
   * @param updateData 更新数据
   * @returns 更新后的权限文档或null
   */
  async update(
    id: mongoose.Types.ObjectId | string,
    updateData: Partial<IPermission>
  ): Promise<IPermissionDocument | null> {
    try {
      if (!id) {
        throw new Error('Permission ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid permission ID format');
      }
      
      if (!updateData || Object.keys(updateData).length === 0) {
        throw new Error('Update data is required');
      }
      
      // 检查权限是否存在
      const existingPermission = await Permission.findById(id);
      if (!existingPermission) {
        throw new Error('Permission not found');
      }
      
      // 检查是否为系统权限，系统权限不允许修改某些字段
      if (existingPermission.isSystem) {
        const restrictedFields = ['code', 'type', 'isSystem'];
        const hasRestrictedField = restrictedFields.some(field => updateData.hasOwnProperty(field));
        if (hasRestrictedField) {
          throw new Error('System permissions cannot modify code, type, or isSystem fields');
        }
      }
      
      const updatedPermission = await Permission.findByIdAndUpdate(
        id,
        { ...updateData, updatedAt: new Date() },
        { new: true, runValidators: true }
      ).populate('systemId').populate('parentId');
      
      return updatedPermission;
    } catch (error: any) {
      if (error.code === 11000) {
        const field = Object.keys(error.keyPattern)[0];
        throw new Error(`${field} already exists`);
      }
      throw error;
    }
  }

  /**
   * 删除权限
   * @param id 权限ID
   * @returns 是否删除成功
   */
  async delete(id: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      if (!id) {
        throw new Error('Permission ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid permission ID format');
      }
      
      // 检查权限是否存在
      const permission = await Permission.findById(id);
      if (!permission) {
        throw new Error('Permission not found');
      }
      
      // 检查权限是否可以被删除
      const canDelete = await permission.canBeDeleted();
      if (!canDelete) {
        throw new Error('Permission cannot be deleted because it has associated roles or child permissions');
      }
      
      const result = await Permission.findByIdAndDelete(id);
      return !!result;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取系统内置权限
   * @returns 系统权限文档数组
   */
  async getSystemPermissions(): Promise<IPermissionDocument[]> {
    try {
      return await Permission.getSystemPermissions();
    } catch (error) {
      throw error;
    }
  }

  /**
   * 构建权限树结构
   * @param systemId 系统ID（可选）
   * @returns 权限树结构
   */
  async buildPermissionTree(systemId?: mongoose.Types.ObjectId | string): Promise<any[]> {
    try {
      let objectId: mongoose.Types.ObjectId | undefined;
      
      if (systemId) {
        if (!mongoose.Types.ObjectId.isValid(systemId)) {
          throw new Error('Invalid system ID format');
        }
        objectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      }
      
      return await Permission.buildPermissionTree(objectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 检查权限编码是否存在
   * @param code 权限编码
   * @param excludeId 排除的权限ID
   * @returns 是否存在
   */
  async isCodeExists(code: string, excludeId?: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      if (!code || typeof code !== 'string') {
        throw new Error('Invalid permission code format');
      }
      
      let excludeObjectId: mongoose.Types.ObjectId | undefined;
      if (excludeId) {
        if (!mongoose.Types.ObjectId.isValid(excludeId)) {
          throw new Error('Invalid exclude ID format');
        }
        excludeObjectId = typeof excludeId === 'string' ? new mongoose.Types.ObjectId(excludeId) : excludeId;
      }
      
      return await Permission.isCodeExists(code, excludeObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 检查权限名称是否存在
   * @param name 权限名称
   * @param excludeId 排除的权限ID
   * @returns 是否存在
   */
  async isNameExists(name: string, excludeId?: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      if (!name || typeof name !== 'string') {
        throw new Error('Invalid permission name format');
      }
      
      let excludeObjectId: mongoose.Types.ObjectId | undefined;
      if (excludeId) {
        if (!mongoose.Types.ObjectId.isValid(excludeId)) {
          throw new Error('Invalid exclude ID format');
        }
        excludeObjectId = typeof excludeId === 'string' ? new mongoose.Types.ObjectId(excludeId) : excludeId;
      }
      
      return await Permission.isNameExists(name, excludeObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 批量创建权限
   * @param permissionsData 权限数据数组
   * @returns 创建的权限文档数组
   */
  async batchCreate(permissionsData: Partial<IPermission>[]): Promise<IPermissionDocument[]> {
    try {
      if (!Array.isArray(permissionsData) || permissionsData.length === 0) {
        throw new Error('Permissions data array is required and cannot be empty');
      }
      
      // 验证每个权限数据的必要字段
      for (const permissionData of permissionsData) {
        if (!permissionData.name || !permissionData.code || !permissionData.type) {
          throw new Error('Each permission must have name, code, and type');
        }
      }
      
      return await Permission.batchCreate(permissionsData);
    } catch (error: any) {
      if (error.code === 11000) {
        throw new Error('Duplicate permission code found in batch data');
      }
      throw error;
    }
  }

  /**
   * 更新权限状态
   * @param id 权限ID
   * @param status 状态
   * @returns 更新后的权限文档或null
   */
  async updateStatus(id: mongoose.Types.ObjectId | string, status: number): Promise<IPermissionDocument | null> {
    try {
      if (!id) {
        throw new Error('Permission ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid permission ID format');
      }
      
      if (status !== 0 && status !== 1) {
        throw new Error('Invalid status. Must be 0 (disabled) or 1 (enabled)');
      }
      
      // 检查权限是否存在
      const permission = await Permission.findById(id);
      if (!permission) {
        throw new Error('Permission not found');
      }
      
      // 系统权限不允许禁用
      if (permission.isSystem && status === 0) {
        throw new Error('System permissions cannot be disabled');
      }
      
      const updatedPermission = await Permission.findByIdAndUpdate(
        id,
        { status, updatedAt: new Date() },
        { new: true, runValidators: true }
      ).populate('systemId').populate('parentId');
      
      return updatedPermission;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 查找所有权限（支持条件查询和分页）
   * @param criteria 查询条件
   * @param options 查询选项
   * @returns 权限列表和分页信息
   */
  async findAll(
    criteria: {
      name?: string;
      code?: string;
      type?: string;
      systemId?: mongoose.Types.ObjectId | string;
      parentId?: mongoose.Types.ObjectId | string;
      status?: number;
      isSystem?: boolean;
    } = {},
    options: {
      page?: number;
      limit?: number;
      sort?: string;
      select?: string;
    } = {}
  ): Promise<{ permissions: IPermissionDocument[]; total: number; page: number; totalPages: number }> {
    try {
      const {
        page = 1,
        limit = 10,
        sort = '-createdAt',
        select
      } = options;
      
      // 构建查询条件
      const query: any = {};
      
      if (criteria.name) {
        query.name = { $regex: criteria.name, $options: 'i' };
      }
      
      if (criteria.code) {
        query.code = { $regex: criteria.code, $options: 'i' };
      }
      
      if (criteria.type) {
        query.type = criteria.type;
      }
      
      if (criteria.systemId) {
        if (!mongoose.Types.ObjectId.isValid(criteria.systemId)) {
          throw new Error('Invalid system ID format');
        }
        query.systemId = typeof criteria.systemId === 'string' 
          ? new mongoose.Types.ObjectId(criteria.systemId) 
          : criteria.systemId;
      }
      
      if (criteria.parentId) {
        if (!mongoose.Types.ObjectId.isValid(criteria.parentId)) {
          throw new Error('Invalid parent ID format');
        }
        query.parentId = typeof criteria.parentId === 'string' 
          ? new mongoose.Types.ObjectId(criteria.parentId) 
          : criteria.parentId;
      }
      
      if (criteria.status !== undefined) {
        if (criteria.status !== 0 && criteria.status !== 1) {
          throw new Error('Invalid status. Must be 0 or 1');
        }
        query.status = criteria.status;
      }
      
      if (criteria.isSystem !== undefined) {
        query.isSystem = criteria.isSystem;
      }
      
      // 计算跳过的文档数
      const skip = (page - 1) * limit;
      
      // 构建查询
      let queryBuilder = Permission.find(query)
        .populate('systemId')
        .populate('parentId')
        .sort(sort)
        .skip(skip)
        .limit(limit);
      
      if (select) {
        queryBuilder = queryBuilder.select(select);
      }
      
      // 执行查询
      const [permissions, total] = await Promise.all([
        queryBuilder.exec(),
        Permission.countDocuments(query)
      ]);
      
      const totalPages = Math.ceil(total / limit);
      
      return {
        permissions,
        total,
        page,
        totalPages
      };
    } catch (error) {
      throw error;
    }
  }
}

export default PermissionDAO;